/**
 *  Copyright (C) 2008-2013  Telosys project org. ( http://www.telosys.org/ )
 *
 *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *          http://www.gnu.org/licenses/lgpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.telosys.persistence;

import java.util.List;

import org.telosys.common.dataset.DataSet;
import org.telosys.persistence.dao.SqlRequests;
import org.telosys.persistence.database.DatabaseInfo;
import org.telosys.persistence.sql.Criteria;
import org.telosys.persistence.sql.SqlQuery;

/**
 * Entity persistence API 
 * 
 * @author Laurent GUERIN
 *
 */
public interface PersistenceManager 
{
	/**
	 * This method closes the PersistenceManger
	 */
	public void close() ;
	
	/**
	 * Determines whether the PersistenceManager is open or not.
	 * @return true if open
	 */
	public boolean isOpen();
	
	/**
	 * This method tests whether or not auto commit mode is currently enabled for the underlying connection
	 * @return 
	 */
	public boolean isAutoCommitMode();

	/**
	 * Returns information about the Database associated with this PersistenceManager
	 * @return
	 */
	public DatabaseInfo getDatabaseInfo() ;
	
	/**
	 * Returns entity information (mapping, ... )
	 * @param entityClass
	 * @return
	 */
	public <T> EntityInfo getEntityInfo(Class<T> entityClass) ;
	
	/**
	 * Returns the SQL requests for the given entity class
	 * @return
	 */
	public <T> SqlRequests<T> getSqlRequests(Class<T> entityClass) ;
	
	/**
	 * Returns the transaction associated with the underlying connection
	 * @return
	 */
	public PersistenceTransaction getTransaction() ;

	/**
	 * Returns the number identifying the PersistanceManger instance
	 * @return a number from 1 to N (or 0 for a Proxy)
	 */
	public int getInstanceId();

	//-------------------------------------------------------------------------------------------------------------------
    // LOAD
    //-------------------------------------------------------------------------------------------------------------------
	/**
	 * Try to load the given entity <br>
	 * The Primary Key attribute(s) of the entity must be set before calling this method<br>
	 * If found the entity attributes are set, if not found the entity is not modified <br>
	 * @param entity the entity instance to load 
	 * @return true if found and loaded, false if not found
	 */
	public boolean load(Object entity) ; 
	
    /**
	 * Try to load the given entity like with 'load' method, but with a pessimistic locking <br>
     * @param entity entity the entity instance to load 
     * @return true if found and loaded, false if not found
     */
    public boolean loadForUpdate(Object entity) ; 

    /**
     * Try to load an instance of the given class using the given values as key parts 
     * @param entityClass the class of the instance to be loaded
     * @param keyValues the list of key parts values ( in the order defined in the mapping )
     * @return
     */
    public <T> T loadByKey(Class<T> entityClass, Object ... keyValues ) ; 

    /**
     * Try to load an instance of the given class using the given values as key parts<br>
     * with a pessimistic locking
     *  
     * @param entityClass the class of the instance to be loaded
     * @param keyValues the list of key parts values ( in the order defined in the mapping )
     * @return
     */
    public <T> T loadByKeyForUpdate(Class<T> entityClass, Object ... keyValues ) ;
    
    /**
     * Try to load a single instance referenced by a link <br>
     * can be used only if there's only one link for the given class (else the link name is required)
     * @param referencedObjectClass the type of the instance referenced by the link
     * @param entity the entity holding the reference (origin of the link)
     * @return the referencedInstance (or null if none)
     */
    public <T> T loadLink(Class<T> referencedObjectClass, Object entity ) ;

    /**
     * Try to load a single instance referenced by a link 
     * @param referencedObjectClass the type of the instance referenced by the link
     * @param entity the entity holding the reference (origin of the link)
     * @param linkName the name of the link to be used
     * @return the referencedInstance (or null if none)
     */
    public <T> T loadLink(Class<T> referencedObjectClass, Object entity, String linkName ) ;

    /**
     * Try to load a list of instance referenced by a "to many" link <br>
     * @param referencedObjectClass the type of instances referenced by the link
     * @param entity the entity at the origin of the link
     * @return
     */
    public <T> List<T> loadLinks(Class<T> referencedObjectClass, Object entity ) ;
    
    /**
     * Try to load a list of instance referenced by a "to many" link <br>
     * @param referencedObjectClass the type of instances referenced by the link
     * @param entity the entity at the origin of the link
     * @param linkName the name of the link to be used
     * @return
     */
    public <T> List<T> loadLinks(Class<T> referencedObjectClass, Object entity, String linkName ) ;
    
    //-------------------------------------------------------------------------------------------------------------------
    // SAVE
    //-------------------------------------------------------------------------------------------------------------------
	public void save(Object entity) ;

    //-------------------------------------------------------------------------------------------------------------------
    // DELETE
    //-------------------------------------------------------------------------------------------------------------------
	public boolean delete(Object entity) ; 

	//-------------------------------------------------------------------------------------------------------------------
    // UPDATE
    //-------------------------------------------------------------------------------------------------------------------
	public boolean update(Object entity) ; 
	
    //-------------------------------------------------------------------------------------------------------------------
    // INSERT
    //-------------------------------------------------------------------------------------------------------------------
	/**
	 * Inserts the given entity in the table <br>
	 * If the Primary Key already exists (and is not an auto-incremented key) an Exception is thrown <br>
	 * If the Primary Key is auto-incremented, the insert always creates a new record in the table<br>
	 * and the key attribute of the entity is set with the generated key.
	 * @param entity
	 */
	public void insert(Object entity) ; 

	public long insertKeyGen(Object entity) ; 
	
    //-------------------------------------------------------------------------------------------------------------------
    // EXISTS
    //-------------------------------------------------------------------------------------------------------------------
	public boolean exists(Object entity) ; 
	
    //-------------------------------------------------------------------------------------------------------------------
    /**
     * Load a list of entities according with the given query
     * @param query
     * @return
     */
    public <T> List<T> loadByQuery( Query<T> query ) ;

    /**
     * Load a list of entities according with the given query and add it to the given list
     * @param query
     * @param list the list where to add the result
     * @return
     */
    public <T> int loadByQuery( Query<T> query, List<T> list );

    /**
     * Load all the entities of a table
     * @param entityClass
     * @return a LinkedList containing all the entities
     */
    public <T> List<T> loadAll( Class<T> entityClass ) ; 
    
    /**
     * Load all the entities of a table with an "order by" clause
     * @param entityClass
     * @param orderBy the SQL "order by ... " string
     * @return
     */
    public <T> List<T> loadAll( Class<T> entityClass, String orderBy ) ;
    
    //-------------------------------------------------------------------------------------------------------------------
    // INSERT LIST
    //-------------------------------------------------------------------------------------------------------------------
    public int insert(List<? extends Object> list ) ; 

    public int insert(List<? extends Object> list, Class<?> entityClass) ; 

    //-------------------------------------------------------------------------------------------------------------------
    // UPDATE LIST
    //-------------------------------------------------------------------------------------------------------------------
    public int update(List<? extends Object> list ) ; 
    
    public int update(List<? extends Object> list, Class<?> entityClass ) ; 

    //-------------------------------------------------------------------------------------------------------------------
    // SAVE LIST
    //-------------------------------------------------------------------------------------------------------------------
// To be added ???
//    public int save(List<? extends Object> list, Class<?> entityClass ) ; 

    //-------------------------------------------------------------------------------------------------------------------
    // DELETE LIST
    //-------------------------------------------------------------------------------------------------------------------
    public int delete(List<? extends Object> list ) ;  

    public int delete(List<? extends Object> list, Class<?> entityClass ) ; 
	
    
    

    //-------------------------------------------------------------------------------------------------------------------
    // DELETE BY QUERY
    //-------------------------------------------------------------------------------------------------------------------
    public int delete(Query<?> query) ; 
	
    //-------------------------------------------------------------------------------------------------------------------
    // COUNT WITH QUERY
    //-------------------------------------------------------------------------------------------------------------------
    public int count(Query<?> query) ; 
	
    public int countAll(Class<?> entityClass) ; 
	
    
    //-------------------------------------------------------------------------------------------------------------------
    // QUERY ALL
    //-------------------------------------------------------------------------------------------------------------------
    public <T> Query<T> createQueryAll( Class<T> entityClass ) ; 

    public <T> Query<T> createQueryAll( Class<T> entityClass, String orderBy ) ; 

    //-------------------------------------------------------------------------------------------------------------------
    // QUERY
    //-------------------------------------------------------------------------------------------------------------------
    public <T> Query<T> createQuery(Class<T> entityClass, String criteria) ; 

    public <T> Query<T> createQuery(Class<T> entityClass, String criteria, String orderBy) ; 
    
    //-------------------------------------------------------------------------------------------------------------------
    // QUERY WITH CRITERIA
    //-------------------------------------------------------------------------------------------------------------------
	public <T> Query<T> createQuery(Class<T> entityClass, Criteria criteria );
    
	public <T> Query<T> createQuery(Class<T> entityClass, Criteria criteria, String sQueryEndOfSelect);
	
    //-------------------------------------------------------------------------------------------------------------------
    // DATASET
    //-------------------------------------------------------------------------------------------------------------------
    public int countDataSetRows( SqlQuery query ) ;
    
    public DataSet loadDataSet( SqlQuery query ) ; 
	
    public void loadDataSet( SqlQuery query, DataSet dataset ) ; 
	
	/**
	 * Returns a new SqlQuery instance based on the SQL request identified by the given name<br>
	 * The SQL request is loaded from a ".sql" file with the same name (searched by ClassPath)
	 * @param name 
	 * @return
	 */
	public SqlQuery getNamedQuery(String name);

    //-------------------------------------------------------------------------------------------------------------------
    // SEQUENCE
    //-------------------------------------------------------------------------------------------------------------------
    /**
     * Return the next value from the given sequence <br>
     * NB : not supported by all the databases 
     * @param sequenceName the name of the sequence to be used
     * @return
     */
    public long sequenceNextVal( String sequenceName ) ;
    
}
